#include <iostream>
using namespace std;

// 设置一个不可以被拷贝的类
class BanCopy
{
public:

	BanCopy(int a)
		:_data(a)
	{}

private:
	// 把拷贝和赋值函数私有化
	BanCopy(const BanCopy& x) = delete;
	BanCopy& operator=(const BanCopy& x) = delete;

	int _data;
};

int main1()
{
	BanCopy bp(1);
	// 不允许拷贝赋值
	// -> 报错 BanCopy bp2(bp);
	return 0;
}


// 设置一个只能再堆上开辟空间的类
// 只能在堆上开辟空间，堆上就是new出来的空间
class OnlyInHeap
{
public:
	static OnlyInHeap* CreatSpace()
	{
		return new OnlyInHeap(1);
	}

	void Print()
	{
		cout << _data << endl;
	}

private:
	OnlyInHeap(const int data)
		:_data(data)
	{}
	OnlyInHeap(const OnlyInHeap& x) = delete;
	OnlyInHeap& operator=(const OnlyInHeap& x) = delete;

	int _data;
};


int main2()
{
	OnlyInHeap* tem = OnlyInHeap::CreatSpace();
	tem->Print();

	// 因为拷贝构造和赋值都被禁用 所以拷贝和赋值都不被允许
	// OnlyInHeap tem2(tem);
	return 0;
}



// 设置一个类只能在栈上开辟空间
class OnlyInStack
{
public:
	static OnlyInStack CreatSpace()
	{
		OnlyInStack tem;
		return tem;
	}

	void Print()
	{
		cout << _data << endl;
	}

	// 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉
	// StackOnly obj = StackOnly::CreateObj();
	// StackOnly* ptr3 = new StackOnly(obj);
	void* operator new(size_t size) = delete;
	void operator delete(void* tem) = delete;

private:
	OnlyInStack()
		:_data(1)
	{}

	int _data;
};

int main4()
{
	OnlyInStack sk = OnlyInStack::CreatSpace();

	sk.Print();

	return 0;
}

// 懒汉模式
class AutoCreat
{
public:
	static AutoCreat& GetAutoObj()
	{
		return _ac;
	}

	AutoCreat(const AutoCreat& tem) = delete;
	AutoCreat& operator=(const AutoCreat& tem) = delete;

private:
	AutoCreat()
		:_data(1)
	{}

	int _data;
	// main 函数开始时 这个类成员已经创建
	static AutoCreat _ac;
};

// 类中 static 修饰的变量需要声明才可使用
// 声明如下
AutoCreat AutoCreat::_ac;

int main3()
{
	// 在main函数还没开始前就已经创建完 _ac 的对象

	AutoCreat& tem = AutoCreat::GetAutoObj();

	return 0;
}


// 饿汉模式
class HungryMan
{
public:
	static HungryMan* AutoCreat()
	{
		if (tem == nullptr)
		{
			tem = new HungryMan;
		}
		return tem;
	}

private:
	HungryMan()
		:_data(1)
	{}
	HungryMan(const HungryMan& tem) = delete;
	HungryMan& operator=(const HungryMan& tem) = delete;

	int _data;
	static HungryMan* tem;
};

// 对这个tem对象进行初始化
HungryMan* HungryMan::tem = nullptr;

int main()
{
	HungryMan* obj = HungryMan::AutoCreat();

	return 0;
}